package recast

// #cgo CFLAGS: -I ${SRCDIR}/recast_cpp
// #cgo LDFLAGS: -L ${SRCDIR}/lib -lnavmesh -lstdc++ -lm
// #include "c_navmesh.h"
// #include <stdlib.h>
import "C"
import (
	"gos/bases/gpool"
	"unsafe"
)

type Recast struct {
	cptr *C.CNavMesh
}

// NewRecast 创建recast
func NewRecast() *Recast {
	return &Recast{
		cptr: newCNavMesh(),
	}
}

// DeleteRecast 销毁recast
func (p *Recast) DeleteRecast() {
	deleteCNavMesh(p.cptr)
}

// Load 加载recast地图资源
func (p *Recast) Load(path string) bool {
	Path := C.CString(path)
	ok := p.loadCNavMesh(Path)
	C.free(unsafe.Pointer(Path))
	return bool(ok)
}

// RandomFindPath 随机寻路，返回寻路点和路点长度
func (p *Recast) RandomFindPath() (bool, []float32, int) {
	var size C.int
	result := make([]float32, 8192*3)
	// result := GetFloat32Slice()
	ok := p.randomFindPathCNavMesh((*C.float)(&result[0]), &size)
	return bool(ok), result, int(size)
}

// FindPath 寻路 返回寻路点和路点长度
func (p *Recast) FindPath(startPos []float32, endPos []float32) (bool, []float32, int) {
	var size C.int
	result := make([]float32, 8192*3)
	sPos := (*C.float)(&startPos[0])
	ePos := (*C.float)(&endPos[0])
	rList := (*C.float)(&result[0])
	ok := p.findPathCNavMesh(sPos, ePos, rList, &size)
	return bool(ok), result, int(size)
}

// FindRandomPoint 获取随机起点和结束点
func (p *Recast) FindRandomPoint() (bool, []float32, []float32) {
	startPos := make([]float32, 3)
	endPos := make([]float32, 3)
	ok := p.findRandomPointCNavMesh((*C.float)(&startPos[0]), (*C.float)(&endPos[0]))
	return bool(ok), startPos, endPos
}

func (p *Recast) loadCNavMesh(path *C.char) C.bool {
	return C.Load(p.cptr, path)
}

func (p *Recast) randomFindPathCNavMesh(result *C.float, size *C.int) C.bool {
	return C.RandomFindPath(p.cptr, result, size)
}

func (p *Recast) findPathCNavMesh(startPos *C.float, endPos *C.float, result *C.float, size *C.int) C.bool {
	return C.FindPath(p.cptr, startPos, endPos, result, size)
}

func (p *Recast) findRandomPointCNavMesh(startPos *C.float, endPos *C.float) C.bool {
	return C.FindRandomPoint(p.cptr, startPos, endPos)
}

func newCNavMesh() *C.CNavMesh {
	p := C.NewCNavMesh()
	return (*C.CNavMesh)(p)
}

func deleteCNavMesh(p *C.CNavMesh) {
	C.DeleteMCNavMesh(p)
}

type Float32Slice struct {
	List []float32
}

var float32SlicePool = gpool.New(func() any {
	return &Float32Slice{List: make([]float32, 8192*3)}
})

func GetFloat32Slice() *Float32Slice {
	return float32SlicePool.Get().(*Float32Slice)
}

func (f *Float32Slice) Return() {
	f.List = f.List[:0]
	float32SlicePool.Put(f)
}
